from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional, BinaryIO, Union, Tuple
from dataclasses import dataclass
from datetime import datetime


@dataclass
class LoginCredentials:
    """登录凭据基类"""
    provider: str  # 云盘提供商标识
    username: Optional[str] = None
    password: Optional[str] = None
    token: Optional[str] = None
    extra_params: Optional[Dict[str, Any]] = None


@dataclass
class PersistentLoginInfo:
    """持久化登录信息"""
    provider: str
    token: Optional[str] = None
    cookies: Optional[Dict[str, str]] = None
    expires_at: Optional[datetime] = None
    extra_data: Optional[Dict[str, Any]] = None


@dataclass
class AccountInfo:
    """账号信息"""
    username: str
    total_space: int  # 总空间（字节）
    used_space: int   # 已用空间（字节）
    available_space: int  # 可用空间（字节）
    extra_info: Optional[Dict[str, Any]] = None


@dataclass
class FileInfo:
    """文件信息"""
    name: str
    path: str
    is_dir: bool
    size: Optional[int] = None
    md5: Optional[str] = None
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None
    extra_info: Optional[Dict[str, Any]] = None


@dataclass
class TrashItem:
    """回收站项目"""
    name: str
    original_path: str
    deleted_at: datetime
    size: Optional[int] = None
    is_dir: bool = False
    extra_info: Optional[Dict[str, Any]] = None


class BaseCloudClient(ABC):
    """云盘客户端基类，定义所有云盘需要实现的标准接口"""
    
    def __init__(self, provider: str):
        self.provider = provider
        self.is_authenticated = False
        self.persistent_info: Optional[PersistentLoginInfo] = None
    
    # ==============================
    # 登录验证接口（可选实现）
    # ==============================
    
    def validate_login(self, provider: str, username: str) -> bool:
        """
        验证登录状态
        默认实现：如果客户端已认证且登录有效则返回True
        各云盘可以根据需要重写此方法
        
        Args:
            provider: 云盘提供商
            username: 用户名
            
        Returns:
            bool: 验证是否通过，默认返回True（验证成功）
        """
        # 默认实现：检查基本的认证状态
        if hasattr(self, 'is_authenticated') and hasattr(self, 'is_login_valid'):
            return self.is_authenticated and self.is_login_valid()
        
        # 如果没有相关属性，默认返回True（验证成功）
        return True
    
    # ==============================
    # 登录认证接口（必须实现）
    # ==============================
    
    @abstractmethod
    def login(self, credentials: LoginCredentials) -> PersistentLoginInfo:
        """
        使用账号密码等凭据进行登录
        返回持久化登录信息用于后续免登录使用
        """
        pass
    
    @abstractmethod
    def login_with_persistent_info(self, persistent_info: PersistentLoginInfo) -> bool:
        """
        使用持久化登录信息进行登录
        返回True表示登录成功，False表示需要重新登录
        """
        pass
    
    @abstractmethod
    def refresh_login(self) -> Optional[PersistentLoginInfo]:
        """
        刷新登录状态，返回新的持久化信息
        如果无法刷新则返回None
        """
        pass
    
    @abstractmethod
    def logout(self) -> bool:
        """登出"""
        pass
    
    @abstractmethod
    def is_login_valid(self) -> bool:
        """检查当前登录状态是否有效"""
        pass
    
    @abstractmethod
    def get_cached_token(self) -> bool:
        """获取当前缓存的token信息供外部存储"""
        pass
    
    # ==============================
    # 文件管理接口（必须实现）
    # ==============================
    
    @abstractmethod
    def upload_file(self, file_stream: Union[bytes, BinaryIO], remote_path: str, **kwargs) -> bool:
        """上传文件"""
        pass
    
    @abstractmethod
    def download_file_stream(self, remote_path: str) -> BinaryIO:
        """下载文件流"""
        pass
    
    @abstractmethod
    def get_download_url(self, remote_path: str, expires_in: int = 3600) -> str:
        """获取下载链接"""
        pass
    
    @abstractmethod
    def list_files(self, remote_path: str = "/") -> List[FileInfo]:
        """列出目录下的文件"""
        pass
    
    @abstractmethod
    def get_file_info(self, remote_path: str) -> FileInfo:
        """获取文件信息"""
        pass
    
    @abstractmethod
    def create_folder(self, remote_path: str) -> bool:
        """创建文件夹"""
        pass
    
    @abstractmethod
    def delete_file(self, remote_path: str, permanent: bool = False) -> bool:
        """删除文件或文件夹"""
        pass
    
    @abstractmethod
    def move_file(self, src_path: str, dst_path: str) -> bool:
        """移动文件或文件夹"""
        pass
    
    @abstractmethod
    def copy_file(self, src_path: str, dst_path: str) -> bool:
        """复制文件或文件夹"""
        pass
    
    @abstractmethod
    def rename_file(self, remote_path: str, new_name: str) -> bool:
        """重命名文件或文件夹"""
        pass
    
    @abstractmethod
    def file_exists(self, remote_path: str) -> bool:
        """检查文件是否存在"""
        pass
    
    # ==============================
    # 秒传接口（可选实现）
    # ==============================
    
    def check_quick_upload(self, file_md5: str) -> bool:
        """检查是否支持秒传，默认不支持"""
        return False
    
    def quick_upload(self, file_md5: str, remote_path: str, **kwargs) -> bool:
        """秒传文件，默认抛出未实现异常"""
        raise NotImplementedError("Quick upload not supported")
    
    # ==============================
    # 账号信息接口（可选实现）
    # ==============================
    
    def get_account_info(self) -> Optional[AccountInfo]:
        """获取账号信息，默认返回None"""
        return None
    
    # ==============================
    # 回收站接口（可选实现）
    # ==============================
    
    def list_trash(self) -> List[TrashItem]:
        """列出回收站内容，默认返回空列表"""
        return []
    
    def restore_from_trash(self, original_path: str, target_path: Optional[str] = None) -> bool:
        """从回收站恢复文件，默认不支持"""
        return False
    
    def delete_from_trash(self, original_path: str) -> bool:
        """从回收站永久删除文件，默认不支持"""
        return False
    
    def empty_trash(self) -> int:
        """清空回收站，返回删除的文件数量，默认返回0"""
        return 0
    
    def get_trash_item_info(self, original_path: str) -> Optional[TrashItem]:
        """获取回收站项目信息，默认返回None"""
        return None